package com.abc.example.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.abc.example.common.constants.Constants;
import com.abc.example.service.AccountCacheService;

import io.gitee.shengzheng1999.esbcommon.common.utils.ObjListUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.ReflectUtil;
import io.gitee.shengzheng1999.esbcommon.vo.common.Page;
import com.abc.example.exception.BaseException;
import com.abc.example.exception.ExceptionCodes;

/**
 * @className		: BaseService
 * @description	: 服务类基类
 * @summary		:
 * @history		:
 * ------------------------------------------------------------------------------
 * date			version		modifier		remarks                   
 * ------------------------------------------------------------------------------
 * 2021/01/01	1.0.0		sheng.zheng		初版
 *
 */
@Service
public class BaseService {
	// 账户缓存服务
	@Autowired
	protected AccountCacheService accountCacheService;
	
	// 测试开关
	protected boolean debug = false;
	
	// debug的getter
	public boolean getDebug() {
		return debug;
	}
	
	// debug的setter
	public void setDebug(boolean debug) {
		this.debug = debug; 
	}
	
	// ===================================================================
	// 输入参数检查的相关公共方法
	
	// -------------------------------------------------------------------
	// 检查输入参数是否缺失及数据格式合规性
	
	/**
	 * 
	 * @methodName		: checkValidForParams
	 * @description	: 检查输入参数是否缺失及数据格式合规性，子类根据需要重载此方法
	 * @param request	: request对象
	 * @param methodName: 方法名称
	 * @param params	: 输入参数
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkValidForParams(HttpServletRequest request,String methodName, Object params) {
		
	}
	
	// -------------------------------------------------------------------
	// 检查主键对象是否存在	
	
	/**
	 * 
	 * @methodName		: checkKey
	 * @description	: 检查键值，子类根据需要重载此方法
	 * @summary			: 适用于单一键或组合键
	 * @param keyPropName: 键属性名，组合键使用逗号分隔
	 * @param propValue	: 属性值，组合键使用Object数组
	 * @return			: 返回实体类对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public Object checkKey(String keyPropName, Object propValue) {
		if (propValue == null) {
			throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,"missing key field:" + keyPropName);	
		}
		return null;
	}	
	
	/**
	 * 
	 * @methodName		: checkKeys
	 * @description	: 检查主键对象是否存在，如存在，则返回相关对象
	 * @param params	: 包括key的字典
	 * @param propName	: 主键属性字段名，组合键用逗号分隔
	 * @return			: 返回实体类对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public Object checkKeys(Map<String,Object> params, String propName) {		
		if (propName.indexOf(",") == -1) {
			// 单一字段主键
			if(params.containsKey(propName)) {
				// 如果包含主键字段
				Object oVal = params.get(propName);
				Object item = checkKey(propName,oVal);
				return item;
			}else {
				// 如果缺失主键字段
				throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,"missing key field:" + propName);				
			}
		}else {
			// 组合键
			String[] keyNames = propName.split(","); 
			int len = keyNames.length;
			Object[] oValues = new Object[len];
			for(int i = 0; i < len; i++) {
				String keyName = keyNames[i];
				if(params.containsKey(keyName)) {
					Object oVal = params.get(keyName);
					oValues[i] = oVal;
				}else {
					throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,"missing key field:" + keyName);
				}
			}
			Object item = checkKey(propName,oValues);
			return item;
		}
	}	
		
	// -------------------------------------------------------------------
	// 检查外键对象是否存在
	
	/**
	 * 
	 * @methodName		: checkRefKeys
	 * @description	: 检查参数字典中外键对象是否存在
	 * @param <T>		: 泛型类型，实体类对象类
	 * @param params	: Map<String,Object>类型字典
	 * @param item		: 实体对象
	 * @param propNames	: 外键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkRefKeys(Map<String,Object> params, T item, String[] propNames) {
		for(String propName : propNames) {
			if (propName.indexOf(",") == -1) {
				// 非组合外键
				if (params.containsKey(propName)) {
					// 如果包含此外键字段值
					Object oVal = params.get(propName);
					Object oldValue = ReflectUtil.getValue(item, propName);
					if (!isSameValue(oVal,oldValue)) {
						// 与原值不同，则检查
						checkKey(propName,oVal);						
					}
				}
			}else {
				// 组合外键
				String[] refKeyNames = propName.split(","); 
				int len = refKeyNames.length;
				Object[] oValues = new Object[len];
				// 组合外键可能没有全部在params字典中，此时从item中取值
				// 组合键是否有修改
				boolean bChange = false;
				for(int i = 0; i < len; i++) {
					String refKeyName = refKeyNames[i];
					Object oldValue = ReflectUtil.getValue(item, refKeyName);
					if (params.containsKey(refKeyName)) {
						// 如果包含此外键字段值
						Object oVal = params.get(refKeyName);
						oValues[i] = oVal;
						if (!isSameValue(oVal,oldValue)) {
							bChange = true;
						}
					}else {
						// 为对象原属性值
						oValues[i] = oldValue;
					}
				}
				if (bChange) {
					// 如果有变化，则检查
					checkKey(propName,oValues);					
				}
			}
		}
	}
	
	/**
	 * 
	 * @methodName		: isSameValue
	 * @description	: 比较两个对象值是否相同，考虑到数据类型可能不同，使用字符串比较
	 * @param oValue1	: 对象1的值
	 * @param oValue2	: 对象2的值
	 * @return			: 相同返回true，否则为false
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/20	1.0.0		sheng.zheng		初版
	 *
	 */
	public boolean isSameValue(Object oValue1,Object oValue2) {
		boolean bRet = false;
		if (oValue1 != null) {
			if (oValue2 != null) {
				// 均非空
				if (oValue1.toString().equals(oValue2.toString())) {
					// 字符串值相同
					bRet = true;
				}
			}
		}else {
			if (oValue2 == null) {
				// 均为空
				bRet = true;
			}
		}
		return bRet;
	}
	
	/**
	 * 
	 * @methodName		: checkRefKeys
	 * @description	: 检查参数字典中外键对象是否存在
	 * @param <T>		: 泛型类型，实体类对象类
	 * @param params	: Map<String,Object>类型字典
	 * @param item		: 实体对象
	 * @param propNames	: 外键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkRefKeys(Map<String,Object> params, String[] propNames) {
		for(String propName : propNames) {
			if (propName.indexOf(",") == -1) {
				// 非组合外键
				if (params.containsKey(propName)) {
					// 如果包含此外键字段值
					Object oVal = params.get(propName);
					checkKey(propName,oVal);						
				}
			}else {
				// 组合外键
				String[] refKeyNames = propName.split(","); 
				int len = refKeyNames.length;
				Object[] oValues = new Object[len];
				// 组合外键可能没有全部在params字典中
				// 组合键是否完整
				boolean bComplete = true;
				for(int i = 0; i < len; i++) {
					String refKeyName = refKeyNames[i];
					if (params.containsKey(refKeyName)) {
						// 如果包含此外键字段值
						Object oVal = params.get(refKeyName);
						oValues[i] = oVal;
					}else {
						bComplete = false;
						break;
					}
				}
				if (bComplete) {
					// 如果完整，则检查
					checkKey(propName,oValues);					
				}
			}
		}
	}	
	
	/**
	 * 
	 * @methodName		: checkRefKeys
	 * @description	: 批量检查对象列表中外键对象是否存在，遇到第一个异常即中止
	 * @summary			: 要考虑检查的效率，同一属性值只需检查一次
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 实体类对象列表
	 * @param propNames	: 外键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkRefKeys(List<T> itemList, String[] propNames) {
		// 已检查项字典，key为：属性名_属性值，value为相关属性值
		Map<String,Object> checkMap = new HashMap<String,Object>();
		// 异常提示，显示T类型对象
		String prompt = "";

		for(T item : itemList) {
			for(String propName : propNames) {
				try {
					if (propName.indexOf(",") == -1) {
						// 非组合外键
						Object oVal = ReflectUtil.getValue(item, propName);
						String sValue = "";
						if (oVal == null) {
							// 如果外键属性值允许为null作为例外值，保护性处理
							sValue = "null";
						}else {
							sValue = oVal.toString();
						}
						String key = String.format("%s_%s", propName,sValue);
						if (!checkMap.containsKey(key)) {
							// 如果未检查，则检查
							checkKey(propName,oVal);
							// 加入检查字典
							checkMap.put(key, oVal);
						}						
					}else {
						// 组合外键
						String[] refKeyNames = propName.split(","); 
						int len = refKeyNames.length;
						Object[] oValues = new Object[len];
						String key = propName;
						String sValue = "";
						for(int i = 0; i < len; i++) {
							String refKeyName = refKeyNames[i];
							Object oVal = ReflectUtil.getValue(item, refKeyName);
							oValues[i] = oVal;
							if (oVal == null) {
								sValue = "null";
							}else {
								sValue = oVal.toString();
							}	
							key += "_" + sValue;
						}
						if (!checkMap.containsKey(key)) {
							// 如果未检查，则检查
							checkKey(propName,oValues);
							
							// 加入检查字典
							checkMap.put(key, oValues);							
						}
					}
				}catch(Exception e) {
					prompt = item.toString();
					throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,prompt + ":" + e.getMessage());
				}
			}
		}
	}		
	
	/**
	 * 
	 * @methodName		: checkRefKeys
	 * @description	: 检查对象中外键对象是否存在
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param item		: 实体对象
	 * @param propNames	: 外键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkRefKeys(T item, String[] propNames) {
		for(String propName : propNames) {
			if (propName.indexOf(",") == -1) {
				// 非组合外键
				Object oVal = ReflectUtil.getValue(item, propName);
				checkKey(propName,oVal);
			}else {
				// 组合外键
				String[] refKeyNames = propName.split(","); 
				int len = refKeyNames.length;
				Object[] oValues = new Object[len];
				for(int i = 0; i < len; i++) {
					String refKeyName = refKeyNames[i];
					Object oVal = ReflectUtil.getValue(item, refKeyName);
					oValues[i] = oVal;
				}
				checkKey(propName,oValues);
			}
		}		
	}
	
	// -------------------------------------------------------------------
	// 检查唯一键，包括准唯一键（存在例外值）
	
	/**
	 * 
	 * @methodName		: checkUnique
	 * @description	: 检查属性值的唯一性，子类按需重载此方法
	 * @param propName	: 属性名，如组合唯一键，则使用逗号分隔
	 * @param propValue	: 属性值，如组合唯一键，则使用Object数组
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkUnique(String propName, Object propValue) {
		
	}
	
	/**
	 * 
	 * @methodName		: checkUniques
	 * @description	: 检查参数字典中唯一键参数值的唯一性，输入参数字典与对象属性值比较，
	 * 	如不同，则检查唯一性；如相同，则为对象原有值，不必比较
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param params	: Map<String,Object>类型字典
	 * @param item		: 实体类对象
	 * @param propNames	: 唯一键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkUniques(Map<String,Object> params, T item, String[] propNames) {
		for(String propName : propNames) {
			if (propName.indexOf(",") == -1) {
				// 非组合唯一键
				if (params.containsKey(propName)) {
					// 如果包含此唯一键字段值
					Object oVal = params.get(propName);
					Object oldValue = ReflectUtil.getValue(item, propName);
					if (!isSameValue(oVal,oldValue)) {
						// 与原值不同，则检查
						checkUnique(propName,oVal);						
					}
				}
			}else {
				// 组合唯一键
				String[] uniqueNames = propName.split(","); 
				int len = uniqueNames.length;
				Object[] oValues = new Object[len];
				// 组合唯一键可能没有全部在params字典中，此时从对象item中获取
				boolean bChange = false;
				for(int i = 0; i < len; i++) {
					String uniqueName = uniqueNames[i];
					Object oldValue = ReflectUtil.getValue(item, uniqueName);
					if (params.containsKey(uniqueName)) {
						// 如果包含此外键字段值
						Object oVal = params.get(uniqueName);
						oValues[i] = oVal;
						if (!isSameValue(oVal,oldValue)) {
							bChange = true;
						}
					}else {
						oValues[i] = oldValue;
					}
				}
				if (bChange) {
					// 如果值有变化，则检查
					checkUnique(propName,oValues);					
				}
			}
		}		
	}
	
	/**
	 * 
	 * @methodName		: checkUniques
	 * @description	: 检查对象列表中唯一键属性值的唯一性
	 * @summary			: 要考虑检查的效率，同一属性值只需检查一次
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 实体类对象列表
	 * @param propNames	: 唯一键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkUniques(List<T> itemList, String[] propNames) {
		// 已检查项字典，key为：属性名_属性值，value为相关属性值
		Map<String,Object> checkMap = new HashMap<String,Object>();
		// 异常提示，显示T类型对象
		String prompt = "";

		for(T item : itemList) {
			for(String propName : propNames) {
				try {
					if (propName.indexOf(",") == -1) {
						// 非组合唯一键
						Object oVal = ReflectUtil.getValue(item, propName);
						String sValue = "";
						if (oVal == null) {
							// 如果外键属性值允许为null作为例外值，保护性处理
							sValue = "null";
						}else {
							sValue = oVal.toString();
						}
						String key = String.format("%s_%s", propName,sValue);
						if (!checkMap.containsKey(key)) {
							// 如果未检查，则检查
							checkUnique(propName,oVal);
							// 加入检查字典
							checkMap.put(key, oVal);
						}						
					}else {
						// 组合唯一键
						String[] uniqueNames = propName.split(","); 
						int len = uniqueNames.length;
						Object[] oValues = new Object[len];
						String key = propName;
						String sValue = "";
						for(int i = 0; i < len; i++) {
							String uniqueName = uniqueNames[i];
							Object oVal = ReflectUtil.getValue(item, uniqueName);
							oValues[i] = oVal;
							if (oVal == null) {
								sValue = "null";
							}else {
								sValue = oVal.toString();
							}	
							key += "_" + sValue;
						}
						if (!checkMap.containsKey(key)) {
							// 如果未检查，则检查
							checkUnique(propName,oValues);
							
							// 加入检查字典
							checkMap.put(key, oValues);							
						}
					}
				}catch(Exception e) {
					prompt = item.toString();
					throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,prompt + ":" + e.getMessage());
				}
			}
		}		
	}
	
	/**
	 * 
	 * @methodName		: checkUniques
	 * @description	: 检查对象中唯一键属性值的唯一性
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param item		: 实体类对象
	 * @param propNames	: 唯一键属性字段名数组，组合键使用逗号分隔
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkUniques(T item, String[] propNames) {
		for(String propName : propNames) {
			if (propName.indexOf(",") == -1) {
				// 非组合唯一键
				Object oVal = ReflectUtil.getValue(item, propName);
				checkUnique(propName,oVal);
			}else {
				// 组合唯一键
				String[] uniqueNames = propName.split(","); 
				int len = uniqueNames.length;
				Object[] oValues = new Object[len];
				for(int i = 0; i < len; i++) {
					String uniqueName = uniqueNames[i];
					Object oVal = ReflectUtil.getValue(item, uniqueName);
					oValues[i] = oVal;
				}
				checkUnique(propName,oValues);
			}
		}			
	}
	
	// -------------------------------------------------------------------
	// 检查枚举值有效性
	
	/**
	 * 
	 * @methodName		: checkEnum
	 * @description	: 检查属性值的枚举类型有效性，子类需重载此方法
	 * @param propName	: 属性名
	 * @param propValue	: 属性值
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkEnum(String propName, Object propValue) {
		
	}		
	
	/**
	 * 
	 * @methodName		: checkEnums
	 * @description	: 检查参数字典中，属性为枚举值的有效性
	 * @param params	: 参数字典
	 * @param propNames	: 枚举值属性字段名数组
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkEnums(Map<String,Object> params, String[]propNames) {
		for(String propName : propNames) {
			if (params.containsKey(propName)) {
				// 如果包含此枚举属性字段
				Object oVal = params.get(propName);
				checkEnum(propName,oVal);
			}
		}
	}
	
	/**
	 * 
	 * @methodName		: checkEnums
	 * @description	: 批量检查对象列表中枚举字段值的有效性
	 * @summary			: 要考虑检查的效率，同一属性值只需检查一次
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 对象列表
	 * @param propNames	: 枚举值属性字段名数组
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkEnums(List<T> itemList, String[] propNames) {
		// 已检查项字典，key为：属性名_属性值，value为相关属性值
		Map<String,Object> checkMap = new HashMap<String,Object>();
		// 异常提示，显示T类型对象
		String prompt = "";

		for(T item : itemList) {
			for(String propName : propNames) {
				try {
					Object oVal = ReflectUtil.getValue(item, propName);
					String sValue = "";
					if (oVal == null) {
						prompt = item.toString();
						throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,prompt + ": " + propName + " is null");						
					}else {
						sValue = oVal.toString();
					}
					String key = String.format("%s_%s", propName,sValue);
					if (!checkMap.containsKey(key)) {
						// 如果未检查，则检查
						checkEnum(propName,oVal);
						// 加入检查字典
						checkMap.put(key, oVal);
					}						
				}catch(Exception e) {
					prompt = item.toString();
					throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,prompt + ":" + e.getMessage());
				}
			}
		}		
	}	
	
	/**
	 * 
	 * @methodName		: checkEnums
	 * @description	: 检查对象中枚举值有效性
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param item		: 实体对象
	 * @param propNames	: 枚举值属性字段名数组
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkEnums(T item, String[] propNames) {
		for(String propName : propNames) {
			Object oVal = ReflectUtil.getValue(item, propName);
			checkEnum(propName, oVal);
		}
	}
	
	// -------------------------------------------------------------------
	// 检查输入列表是否有重复项
	
	/**
	 * 
	 * @methodName		: checkDuplicates
	 * @description	: 检查对象列表中是否存在重复项
	 * @param <T>		: 泛型类型，可以是基础类型，也可以是实体对象类
	 * @param itemList	: 对象列表
	 * @param fieldMap	: key为字段名称，value为1，表示键值字段。null表示T为基础类型。
	 * @param bThrowError: 发现重复项是否抛出异常。
	 * @return			: 剔除重复项后的对象列表			
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> List<T> checkDuplicates(List<T> itemList,Map<String,Integer> fieldMap,
			boolean bThrowError){
		// 复制列表，不影响输入项
		List<T> newList = new ArrayList<T>(itemList);
		List<T> dupList = new ArrayList<T>();
		// 列表去重处理
		ObjListUtil.removeDuplicate(fieldMap, newList, dupList);
		if (dupList.size() > 0 && bThrowError) {
			// 如果有重复抛出异常
			throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,"duplicate items:" + dupList.toString());			
		}
		
		return newList;
	}
	
	// -------------------------------------------------------------------
	// 检查输入对象列表是否有未赋值的必选字段
	
	/**
	 * 
	 * @methodName		: checkMandatoryFields
	 * @description	: 检查对象列表的必选字段是否满足要求
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 实体对象列表
	 * @param defItem	: 实体对象，为初始创建，各属性值使用默认值
	 * @param mandatoryFields: 必选字段属性名数组
	 * @param escapeFields: 忽略检查的属性名数组(默认值为有效值的属性)
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/19	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkMandatoryFields(List<T> itemList,T defItem,String[] mandatoryFields,
			String[] escapeFields) {
		if (itemList.size() == 0) {
			return;
		}
		
		// 构造忽略默认值的字段字典
		Map<String,Integer> escapeMap = new HashMap<String,Integer>();
		for(String propName : escapeFields) {
			escapeMap.put(propName, 1);
		}
		
		String error = "";
		for(T item : itemList) {
			error = ReflectUtil.checkMandatoryFields(item, defItem, mandatoryFields,escapeMap);
			if (!error.isEmpty()) {
				throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,error);
			}
		}
	}
	
	// -------------------------------------------------------------------
	// 检查参数一致性
	
	/**
	 * 
	 * @methodName		: checkSames
	 * @description	: 批量检查对象列表中规定参数值的一致性
	 * @summary			: 要考虑检查的效率，同一属性值只需检查一次
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 对象列表
	 * @param propNames	: 一致性属性字段名数组
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/18	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void checkSames(List<T> itemList, String[] propNames) {
		// 已检查项字典，key为：属性名_属性值，value为相关属性值
		Map<String,Object> checkMap = new HashMap<String,Object>();
		// 异常提示，显示T类型对象
		String prompt = "";

		for(T item : itemList) {
			for(String propName : propNames) {
				Object oVal = ReflectUtil.getValue(item, propName);
				String sValue = "";
				if (oVal == null) {
					prompt = item.toString();
					throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR,prompt + ": " + propName + " is null");						
				}else {
					sValue = oVal.toString();
				}
				if (!checkMap.containsKey(propName)) {
					checkMap.put(propName, sValue);
				}else {
					String oldValue = (String)checkMap.get(propName);
					if (!oldValue.equals(sValue)) {
						prompt = item.toString();
						throw new BaseException(ExceptionCodes.ARGUMENTS_IS_INCOMPATIBLE,prompt + ":" + propName);						
					}
				}
			}
		}		
	}		
	
	// -------------------------------------------------------------------
	// 使用缓存填充实体对象引用属性值
	
	/**
	 * 
	 * @methodName		: fillRefValue
	 * @description	: 填充实体对象引用属性值，子类根据需要进行重载
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param item2		: 实体类对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/22	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void fillRefValue(T item2) {
		
	}
	
	/**
	 * 
	 * @methodName		: fillRefValue
	 * @description	: 填充实体对象列表的引用属性值，子类根据需要进行重载
	 * @param <T>		: 泛型类型，为实体类对象类
	 * @param itemList	: 实体类对象列表
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/01/22	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void fillRefValue(List<T> itemList) {
		for(T item : itemList) {
			fillRefValue(item);
		}
	}	
	
	// -------------------------------------------------------------------
	// 根据引用对象键值设置引用对象ID值
	public <T> void fillRefId(List<T> itemList,String propName,List<String> errorList,
			Map<T,String> obj2RowNoMap) {
		Map<String,Object> refMap = new HashMap<String,Object>();
		// 异常提示，显示T类型对象
		String prompt = "";		
		for(int i = itemList.size()-1; i>=0; i--) {
			T item = itemList.get(i);
			String row = obj2RowNoMap.get(item);
			Object oValue = ReflectUtil.getValue(item, propName);
			if (oValue == null) {
				prompt = String.format("row[%s]：%s参数值为空",row,propName);
				errorList.add(prompt);
				itemList.remove(i);
				continue;
			}
			String sValue = oValue.toString();
			Object oVal = null;
			if (refMap.containsKey(sValue)) {
				oVal = refMap.get(sValue);
			}else {
				oVal = getRefId(propName,oValue);					
				refMap.put(sValue, oVal);
			}
			if (oVal == null) {
				prompt = String.format("row[%s]：%s对应值%s引用对象不存在",row,propName,sValue);
				errorList.add(prompt);
				itemList.remove(i);
				continue;
			}
			// 设置引用对象ID值
			ReflectUtil.setValue(item, propName, oVal);
		}
	}
	
	/**
	 * 
	 * @methodName		: getRefId
	 * @description	: 获取引用对象ID，子类根据需要进行重载
	 * @param propName	: 引用对象的唯一键属性名
	 * @param oValue	: 唯一键值
	 * @return			: 引用对象ID值
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/02/19	1.0.0		sheng.zheng		初版
	 *
	 */
	public Object getRefId(String propName,Object oValue) {
		return null;
	}
	
	/**
	 * 
	 * @methodName		: getPrompt
	 * @description	: 获取提示信息
	 * @param propName	: 属性名，多个属性用逗号分隔
	 * @param oValue	: 属性值，多个属性用数组表示
	 * @return			: 提示信息
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/02/26	1.0.0		sheng.zheng		初版
	 *
	 */
	public String getPrompt(String propName,Object oValue) {
		String prompt = "";
		if (propName.indexOf(",") == -1) {
			// 非数组
			prompt = propName + "=" + oValue.toString();
		}else {
			String[] propNames = propName.split(",");
			int len = propNames.length;
			if (len > 0) {
				Object[] oValues = (Object[]) oValue;
				prompt = propName + "=";
				for(int i = 0; i < propNames.length; i++) {
					Object oVal = oValues[i];
					if (i == 0) {
						prompt += oVal.toString();
					}else {
						prompt += "," + oVal.toString();
					}
				}				
			}
		}
		return prompt;
	}
	
	/**
	 * 
	 * @methodName		: updateItem
	 * @description	: 批量导入需调用的修改一个对象的方法，子类根据需要重载
	 * @param <T>		: 泛型类型
	 * @param item		: 实体类对象
	 * @param fieldNameList	: 字段名列表
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2024/02/19	1.0.0		sheng.zheng		初版
	 *
	 */
	public <T> void updateItem(HttpServletRequest request,T item, List<String> fieldNameList) {
		
	}		
	
	/**
	 * 
	 * @methodName		: processPageInfo
	 * @description	: 处理分页信息
	 * @param params	: 包含分页信息的map
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public void processPageInfo(Map<String,Object> params) {
    	// 分页处理
    	Integer pageNum = (Integer)params.get("pagenum");
    	if(Objects.isNull(pageNum)) {
    		pageNum = 1;
    	}
    	Integer pageSize = (Integer)params.get("pagesize");
    	if(Objects.isNull(pageSize)) {
    		pageSize = 10;
    	}
    	PageHelper.startPage(pageNum, pageSize);				
	}
	
	/**
	 * 
	 * @methodName		: calcPageInfo
	 * @description	: 计算分页信息
	 * @param pageNum	: 页码
	 * @param pageSize	: 每页条数
	 * @param total		: 总记录数
	 * @return			: Page对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public Page calcPageInfo(int pageNum, int pageSize,long total) {
		Page page = new Page();
		int currentPageNo = pageNum;
		
		if (pageSize <= 0) {
			page.setPageSize(10);
		}else {
			page.setPageSize(pageSize);			
		}
		
		if (pageNum <= 0) {
			currentPageNo = 1;
		}

		// 计算合适的分页
		if (total < (pageNum - 1) * pageSize) {
			currentPageNo = 1;
		}
		
		page.setPageNum(currentPageNo);
		page.setTotal(total);
		
		int pagesize = page.getPageSize();
		int remaider = (int)(total % pagesize);
		if (remaider == 0) {
			// 整除
			page.setPages((int)total/pagesize);
		}else {
			page.setPages((int)total/pagesize + 1);
		}
		
		return page;
	}
		
	
	/**
	 * 
	 * @methodName		: getUserName
	 * @description	: 获取访问账户的用户名
	 * @param request	: request对象
	 * @return			: 访问账户的用户名
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public String getUserName(HttpServletRequest request) {
		String userName = "";
		// 获取accountId
		String accountId = accountCacheService.getId(request);
		// 获取用户名	
		Object userNameObj = accountCacheService.getAttribute(accountId, Constants.USER_NAME);		
		if (userNameObj != null) {
			userName = (String)userNameObj;
		}else {
			// 说明此时accountId无效，或属性"username"未注册			
			return "";			
		}
		return userName;
	}
	
	
	/**
	 * 
	 * @methodName		: checkRigts
	 * @description	: 检查系统管理员权限
	 * @param request	: request对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2022/08/07	1.0.0		sheng.zheng		初版
	 *
	 */
	@SuppressWarnings("unchecked")
	public void checkAdminRigts(HttpServletRequest request) {
		// 检查当前用户是否有系统管理员权限
		String accountId = accountCacheService.getId(request);
		List<Integer> roleIdList = (List<Integer>)accountCacheService.getAttribute(
				accountId, Constants.ROLE_ID_LIST);
		if (roleIdList == null) {
			throw new BaseException(ExceptionCodes.SESSION_DATA_WRONG,"roleIdList");
		}
		if (!roleIdList.contains(Constants.SA_ROLE_ID)) {
			throw new BaseException(ExceptionCodes.NO_RIGHTS);
		}
	}	
}
